
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Laurens
 */
public class Delete_Method_Refactor implements RefactoringMethod
{
    /*
     * Initialization and declaration of variables
     */
    referenceFinder find = new referenceFinder();
    FileEditor fileE = new FileEditor();
    characterList character = new characterList();
    ErrorMessages error = new ErrorMessages();
    /*
     * End of initialization and declaration of variables
     */
    
    /**
     * Constructor does nothing
     */
    public Delete_Method_Refactor()
    {
        //DOES NOTHING
    }
    
    /**
     * This function does the refactoring of deleting a method safely
     * @param parameters
     * @return 
     */
    @Override
    public Vector<String> refactor(Vector<String> parameters)
    {
        /*
         * Creates same look and feel for GUI
         */
        try 
        {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } 
        catch (Exception ex) 
        {
            Logger.getLogger(Rename_Parameter_Refactor.class.getName()).log(Level.SEVERE, null, ex);
        } 
        Vector<String> result = new Vector<String>();
        String path = "";
        String oldMethod = "";
        Vector<String> methodList = new Vector<String>();
        path = parameters.get(0);
        String file = "";
        String classN = "";
        String className = "";
        String location = "";
        String oldMethodOverLoaded = "";
        boolean duplicate = false;
        result.add(path);
        StringTokenizer stClassName = new StringTokenizer(path, "/");
        while(stClassName.hasMoreTokens())
        {
            className = stClassName.nextToken();
        }
        location = path.replace(className, "");
        StringTokenizer st = new StringTokenizer(className, ".");
        classN = st.nextToken();
        if(parameters.isEmpty())
        {
            result.add(error.getErrorMessages("notFound"));
            return result;
        }
        Database db = new Database();
        try
        {
            db.connect();
            db.initializeDB();
            ParserProxy parser = new ParserProxy("FileParser");
            parser.parseString(path);
            methodList = db.getMethod(classN);
        }
        catch(Exception e)
        {
            
        }
        /*
         * Parameters declaration
         */
            if(parameters.get(1) == null)
            {
                if(methodList.size() < 20)
                {
                    Object[] selectionValues2 = new Object[methodList.size()];
                    for(int i = 0; i < methodList.size(); i++)
                    {
                        selectionValues2[i] = methodList.get(i);
                    }
                    oldMethod = JOptionPane.showInputDialog(null, "Please select the method?", "Method Selection", JOptionPane.QUESTION_MESSAGE, null, selectionValues2,"").toString();
                    int count = 0;
                    for(int i = 0; i < methodList.size(); i++)
                    {
                        if(selectionValues2[i].equals(oldMethod))
                        {
                            count++;
                        }
                    }
                    if(count > 1)
                    {
                        duplicate = true;
                    }
                }
                else
                {
                    oldMethod = JOptionPane.showInputDialog("Enter old method");
                }
            }
            else
            {
                oldMethod = parameters.get(1);
            }
            if(!duplicate)
            {
                Vector v = find.referenceFinder(oldMethod, location, classN);
                String paths = "";
                int size = 0;
                size = v.size();
                if(size > 3)
                {
                    size = 3;
                }
                for(int y = 0; y < size; y++)
                {
                    paths += "> " + v.get(y) + "\n";
                }
                if(v.size() > 0)
                {
                    if(v.size() == 1)
                    {
                        result.add("Error, references have been found in other file, for safety reasons the refactoring is cancelled.\nPlease try delete a different method.\n" + v.size() + " reference of " + oldMethod + " found in this file:\n"+paths);
                        return result;
                    }
                    else if(size < 3)
                    {
                        result.add("Error, references have been found in other file, for safety reasons the refactoring is cancelled.\nPlease try delete a different method.\n" + v.size() + " reference\\(s) of " + oldMethod + " found in these files:\n"+paths);
                        return result;
                    }
                    else
                    {
                        result.add("Error, references have been found in other file, for safety reasons the refactoring is cancelled.\nPlease try delete a different method.\n" + v.size() + " references of " + oldMethod + " found in these and more files:\n"+paths+"...");
                        return result;
                    }
                }
            }
            try
            {
                /*
                 * Reads the file needed to do the introduce local extension refactor
                 */
                file = fileE.read(path);
                if(!duplicate)
                {
                    int lineNumbers = 0;
                    int length = 1;
                    Scanner scanner = new Scanner(file);
                    int i = 1;
                    while(scanner.hasNext())
                    {
                        String currentLine = scanner.nextLine();
                        if(currentLine.contains("public"))
                        {
                            for(int p = 0; p < 17; p++)
                            {
                                if(currentLine.contains(" "+character.keywords().get(p)+" "))
                                {
                                    if(currentLine.contains(" "+oldMethod+" "))
                                    {
                                        lineNumbers = i;
                                        length = determineMethodLength(lineNumbers, file);
                                    }
                                    else if(currentLine.contains(" "+oldMethod+"("))
                                    {
                                        lineNumbers = i;
                                        length = determineMethodLength(lineNumbers, file);
                                    }
                                }
                            }
                        }
                        i++;
                    }
                    if(checkIfDeletable(lineNumbers, file, oldMethod))
                    {
                        int confirm = JOptionPane.showConfirmDialog(null, "There is a reference of " + oldMethod + " inside this class. Do you still wish to delete it?\nWe cannot gaurenttee it will conserve external behavior!", "Overwrite?", JOptionPane.YES_NO_OPTION);
                        if(confirm == 0)
                        {
                            result.add(deleteMethodConfirm(lineNumbers, length, file, oldMethod));
                        }
                        else
                        {
                            result.add("Error, refactoring cancelled.");
                        }
                    }
                    else
                    {
                        result.add(deleteMethodConfirm(lineNumbers, length, file, oldMethod));
                    }
                }
                else
                {
                    Vector<String> overloaded = overloadedDelete(file, oldMethod);
                    Vector<Integer> parameterList = getParameterList(file, oldMethod);
                    Object[] selectionOverloaded = new Object[overloaded.size()];
                    Vector<Integer> params = new Vector<Integer>();
                    for(int i = 0; i < overloaded.size(); i++)
                    {
                        selectionOverloaded[i] = overloaded.get(i).trim();
                        params.add(parameterList.get(i));
                    }
                    Vector<Integer> lineNumbersOverloaded = new Vector<Integer>();
                    oldMethodOverLoaded = JOptionPane.showInputDialog(null, "A clash has been found, which overloaded method would you like to delete?", "Method Selection", JOptionPane.QUESTION_MESSAGE, null, selectionOverloaded,"").toString();
                    int cParam = parameters(oldMethodOverLoaded);
                    lineNumbersOverloaded = getLineNumbersOverloaded(oldMethod, file, cParam);
                    int counter = 0;
                    for(int q = 0; q < params.size(); q++)
                    {
                        if(cParam == params.get(q))
                        {
                            counter++;
                        }
                    }
                    if(counter > 1)
                    {
                        result.add("Error, not enough information to do the refactoring.");
                        return result;
                    }
                    int lineNumbers = 0;
                    int length = 1;
                    Scanner scanner = new Scanner(file);
                    int i = 1;
                    while(scanner.hasNext())
                    {
                        String currentLine = scanner.nextLine();
                        if(currentLine.contains("public "))
                        {
                            for(int p = 0; p < 17; p++)
                            {
                                if(currentLine.contains(oldMethodOverLoaded))
                                {
                                    lineNumbers = i;
                                    length = determineMethodLength(lineNumbers, file);
                                }
                            }
                        }
                        else if(currentLine.contains("private "))
                        {
                            for(int p = 0; p < 17; p++)
                            {
                                if(currentLine.contains(oldMethodOverLoaded))
                                {
                                    lineNumbers = i;
                                    length = determineMethodLength(lineNumbers, file);
                                }
                            }
                        }
                        i++;
                    }
                    
                    /*Here comes reference*/
                    Vector v = find.referenceFinderOverload(oldMethod, location, classN, cParam);
                    String paths = "";
                    int size = 0;
                    size = v.size();
                    if(size > 3)
                    {
                        size = 3;
                    }
                    for(int y = 0; y < size; y++)
                    {
                        paths += "> " + v.get(y) + "\n";
                    }
                    if(v.size() > 0)
                    {
                        if(v.size() == 1)
                        {
                            result.add("Error, references have been found in other file, for safety reasons the refactoring is cancelled.\nPlease try delete a different method.\n" + v.size() + " reference of " + oldMethod + " found in this file:\n"+paths);
                            return result;
                        }
                        else if(size < 3)
                        {
                            result.add("Error, references have been found in other file, for safety reasons the refactoring is cancelled.\nPlease try delete a different method.\n" + v.size() + " reference\\(s) of " + oldMethod + " found in these files:\n"+paths);
                            return result;
                        }
                        else
                        {
                            result.add("Error, references have been found in other file, for safety reasons the refactoring is cancelled.\nPlease try delete a different method.\n" + v.size() + " references of " + oldMethod + " found in these and more files:\n"+paths+"...");
                            return result;
                        }
                    }
                    /*End reference*/
                    
                    
                    if(lineNumbersOverloaded.size() > 0)
                    {
                        int confirm = JOptionPane.showConfirmDialog(null, "There is a reference of " + oldMethodOverLoaded + " inside this class. Do you still wish to delete it?\nWe cannot gaurenttee it will conserve external behavior!", "Overwrite?", JOptionPane.YES_NO_OPTION);
                        if(confirm == 0)
                        {
                            result.add(deleteMethodConfirmOverload(lineNumbers, length, file, oldMethod, cParam));
                        }
                        else
                        {
                            result.add("Error, refactoring cancelled.");
                        }
                    }
                    else
                    {
                        result.add(deleteMethodConfirmOverload(lineNumbers, length, file, oldMethod, cParam));
                    }
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
                result.add(error.getErrorMessages("tryFailed"));
                return result;
            }
        return result;
    }

    /**
     * Returns the length of the function you want to delete
     * @param lineNumbers
     * @param file
     * @return 
     */
    public int determineMethodLength(int lineNumbers, String file) 
    {
        Scanner scanner = new Scanner(file);
        int i = 1;
        int length = 1;
        int closedBrackets = 0;
        int openBrackets = 0;        
        while(scanner.hasNext())
        {
            String currentLine = scanner.nextLine();
            if(lineNumbers == i)
            {
                if(currentLine.contains("{"))
                {
                    openBrackets++;
                }
                else
                {
                    currentLine = scanner.nextLine();
                    if(currentLine.contains("{"))
                    {
                        openBrackets++;
                        length++;
                    }
                }
                if(openBrackets!=0)
                {
                    while(openBrackets!=closedBrackets)
                    {
                        String current = scanner.nextLine();
                        if(current.contains("{"))
                        {
                            openBrackets++;
                        }
                        else if(current.contains("}"))
                        {
                            closedBrackets++;
                        }
                        length++;  
                    }
                }
            }
            else
            {
                
            }
            i++;
        }
        return length;
    }
   
    /**
     * Returns a description of the current refactoring method
     * @return 
     */
    @Override
    public String description() 
    {
        return "Safely deletes a certain method in the current class, unless if there is a reference to this method in another class.";
    }
    
    public Vector<String> overloadedDelete(String file, String oldMethod)
    {
        Vector<String> result = new Vector<String>();
        Scanner scanner = new Scanner(file);
        Vector<String> spaces = new Vector<String>();
        spaces.add("");
        spaces.add(" ");
        spaces.add("  ");
        spaces.add("   ");
        spaces.add("    ");
        spaces.add("     ");
        spaces.add("      ");
        spaces.add("       ");
        while(scanner.hasNext())
        {
            String currentLine = scanner.nextLine();
            if(currentLine.contains("public"))
            {
                for(int u = 0;  u < spaces.size(); u++)
                {
                    if(currentLine.contains(" "+oldMethod+spaces.get(u)+"(") )
                    {
                        result.add(currentLine);                        
                    }
                }
            }
            else if(currentLine.contains("private"))
            {
                for(int u = 0;  u < spaces.size(); u++)
                {
                    if(currentLine.contains(" "+oldMethod+spaces.get(u)+"(") )
                    {
                        result.add(currentLine);                        
                    }
                }
            }
            else
            {
                
            }
        }
        return result;
    }

    private Vector<Integer> getParameterList(String file, String oldMethod) 
    {
        Vector<Integer> result = new Vector<Integer>();
        Scanner scanner = new Scanner(file);
        Vector<String> spaces = new Vector<String>();
        spaces.add("");
        spaces.add(" ");
        spaces.add("  ");
        spaces.add("   ");
        spaces.add("    ");
        spaces.add("     ");
        spaces.add("      ");
        spaces.add("       ");
        while(scanner.hasNext())
        {
            String currentLine = scanner.nextLine();
            if(currentLine.contains("public"))
            {
                for(int u = 0;  u < spaces.size(); u++)
                {
                    if(currentLine.contains(" "+oldMethod+spaces.get(u)+"(") )
                    {
                        result.add(parameters(currentLine));                        
                    }
                }
            }
            else if(currentLine.contains("private"))
            {
                for(int u = 0;  u < spaces.size(); u++)
                {
                    if(currentLine.contains(" "+oldMethod+spaces.get(u)+"(") )
                    {
                        result.add(parameters(currentLine));                        
                    }
                }
            }
            else
            {
                
            }
        }
        return result;
    }
    
    private int parameters(String currentLine) 
    {
        int output = 0;
        StringTokenizer st = new StringTokenizer(currentLine, "(");
        st.nextToken();
        String current = "";
        while(st.hasMoreTokens())
        {
            current += st.nextToken();
        }
        String noBrackets = current.trim().substring(0, current.length() - 1);
        if(currentLine.contains("()"))
        {
            return 0;
        }
        else if(currentLine.contains("( )"))
        {
            
        }
        else
        {
            output++;
        }
        StringTokenizer st2 = new StringTokenizer(noBrackets);
        while(st2.hasMoreTokens())
        {
            String current2 = st2.nextToken();
            if(current2.contains(","))
            {
                output++;
            }
        }
        System.out.println(currentLine+"++");
        System.out.println(output+"+");
        return output;
    }
    
    /**
     * Deletes the method at the lineNumber lineNumbers and for a length of length
     * @param lineNumbers
     * @param file
     * @param oldMethod
     * @return 
     */
    public boolean checkIfDeletable(int lineNumbers, String file, String oldMethod) 
    {
        Scanner scanner = new Scanner(file);
        int i = 1;
        Vector<String> spaces = new Vector<String>();
        spaces.add("");
        spaces.add(" ");
        spaces.add("  ");
        spaces.add("   ");
        spaces.add("    ");
        spaces.add("     ");
        spaces.add("      ");
        spaces.add("       ");
        boolean cantDelete = false;
        while(scanner.hasNext())
        {
            String currentLine =  scanner.nextLine();
            if(i != lineNumbers)
            {
                for(int n = 0; n < spaces.size(); n++)
                {
                    if(currentLine.contains(" "+oldMethod+spaces.get(n)+"("))
                    {
                        cantDelete = true;
                        return cantDelete;
                    }   
                }
            }
            else
            {
                cantDelete = false;
            }
            i++;
        }
        return cantDelete;
    }
    
    /**
     * Deletes the method at the lineNumber lineNumbers and for a length of length
     * @param lineNumbers
     * @param length
     * @param file
     * @param oldMethod
     * @return 
     */
    public String deleteMethodConfirm(int lineNumbers, int length, String file, String oldMethod) 
    {
        Vector<String> result = new Vector<String>();
        Scanner scanner = new Scanner(file);
        int i = 1;
        while(scanner.hasNext())
        {
            String currentLine =  scanner.nextLine();
            if(i == lineNumbers)
            {
                i = length + lineNumbers;
                for(int j = 1; j < length; j++)
                {
                    scanner.nextLine();
                }
            }   
            else if(currentLine.contains(" "+oldMethod+"("))
            {
                
            }
            else
            {
                result.add(currentLine);
            }
            i++;
        }
        String output = " ";
        for(int u = 0; u < result.size(); u++)
        {
            output += result.get(u) + "\n";
        }
        return output;
    }

    private Vector<Integer> getLineNumbersOverloaded(String oldMethod, String file, int paramNum) 
    {
        Scanner scanner = new Scanner(file);
        Vector<Integer> result = new Vector<Integer>();
        int i = 1;
        while(scanner.hasNext())
        {
            String currentLine = scanner.nextLine();
            if(!currentLine.contains("public "))
            {
                if(currentLine.contains(" "+oldMethod))
                {
                    if(currentLine.contains("("))
                    {
                        if(parameters(currentLine) == paramNum)
                        {
                            result.add(i);
                        }
                    }
                }
                else
                {

                }
            }
            i++;
        }
        return result;
    }

    private String deleteMethodConfirmOverload(int lineNumbers, int length, String file, String oldMethod, int paramNum) 
    {
        Vector<String> result = new Vector<String>();
        Scanner scanner = new Scanner(file);
        int i = 1;
        Vector<String> spaces = new Vector<String>();
        spaces.add("");
        spaces.add(" ");
        spaces.add("  ");
        spaces.add("   ");
        spaces.add("    ");
        spaces.add("     ");
        spaces.add("      ");
        spaces.add("       ");
        while(scanner.hasNext())
        {
            String currentLine = scanner.nextLine();
            if(i == lineNumbers)
            {
                i = length + lineNumbers;
                for(int j = 1; j < length; j++)
                {
                    scanner.nextLine();
                }
            }   
            else if(currentLine.contains(" "+oldMethod))
            {
                boolean found = false;
                for(int y = 0; y < spaces.size(); y++)
                {
                    if(currentLine.contains(" "+oldMethod+spaces.get(y)+"("))
                    {
                        if(parameters(currentLine) == paramNum)
                        {
                            found = true;
                        }
                    }
                }
                if(found)
                {
                    
                }
                else
                {
                    result.add(currentLine);
                }
            }
            else
            {
                result.add(currentLine);
            }
            i++;
        }
        String output = " ";
        for(int u = 0; u < result.size(); u++)
        {
            output += result.get(u) + "\n";
        }
        return output;
    }
}

